package com.mlnx.device.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mlnx.device.dao.mysql.DeviceMapper;
import com.mlnx.device.entity.Device;
import com.mlnx.device.entity.EcgDevice;
import com.mlnx.device.enums.DeviceType;
import com.mlnx.device.enums.ECGChannelType;
import com.mlnx.device.enums.ECGDeviceRunMode;
import com.mlnx.device.pojo.dto.AutoDetectCmdDto;
import com.mlnx.device.pojo.dto.DeviceCountDTO;
import com.mlnx.device.pojo.dto.DeviceGroupDto;
import com.mlnx.device.pojo.form.ConfigEcgDeviceForm;
import com.mlnx.device.pojo.form.DeviceForm;
import com.mlnx.device.pojo.vo.DeviceCountVO;
import com.mlnx.device.pojo.vo.DeviceGroupVO2;
import com.mlnx.device.pojo.vo.DeviceVO;
import com.mlnx.device.service.*;
import com.mlnx.device.session.manager.MutilDeviceSessionManager;
import com.mlnx.external.push.entity.TPushDevice;
import com.mlnx.external.push.service.TPushDeviceService;
import com.mlnx.mptp.mptp.MpPacket;
import com.mlnx.mptp.mptp.body.Body;
import com.mlnx.mptp.mptp.body.Command;
import com.mlnx.mptp.mptp.body.config.ConfigBody;
import com.mlnx.mptp.mptp.head.QoS;
import com.mlnx.service.base.service.BaseService;
import com.mlnx.service.common.enums.ResponseEnum;
import com.mlnx.service.common.exception.MutilDeviceServiceException;
import io.netty.channel.Channel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by amanda.shan on 2019/10/25.
 */
@Service
public class DeviceServiceIml extends BaseService<DeviceMapper, Device> implements DeviceService {

    @Autowired
    @Override
    public void setBaseMapper(DeviceMapper baseMapper) {
        super.setBaseMapper(baseMapper);
    }

    @Autowired
    private EcgDeviceService ecgDeviceService;

    @Autowired
    private LanyaDeviceService lanyaDeviceService;

    @Autowired
    private XmBpDeviceService xmBpDeviceService;

    @Autowired
    private MutilDeviceSessionManager sessionManager;

    @Autowired
    private TPushDeviceService tPushDeviceService;

    @Autowired
    private DeviceGroupService deviceGroupService;


    @Override
    public Device getDevice(String deviceId) {

        Device device = baseMapper.selectOne(new QueryWrapper<Device>().eq("numeration", deviceId));

        return device;
    }

    @Override
    public Map<String, Device> getDeviceMap(Collection<String> deviceIds) {

        Map<String, Device> deviceMap = new HashMap<>();

        List<Device> devices = baseMapper.selectList(new QueryWrapper<Device>().in("numeration", deviceIds));
        if (devices != null) {
            devices.stream().forEach(device -> deviceMap.put(device.getNumeration(), device));
        }

        return deviceMap;
    }

    @Override
    @Transactional
    public void addDevice(DeviceForm deviceForm) {
        Device device = new Device();
        device.setNumeration(deviceForm.getNumeration());
        device.setDeviceTypeId(DeviceType.valueOf(deviceForm.getDeviceType()));
        device.setPatientId(0);

        save(device);

        if (deviceForm.getDeviceType().equals(DeviceType.ECG_DEVICE.name())) {
            try {
                EcgDevice ecgDevice = new EcgDevice();
                ecgDevice.setId(device.getId());
                ecgDevice.setEcgDeviceRunMode(ECGDeviceRunMode.valueOf(deviceForm.getRunMode()));
                ecgDevice.setEcgChannelType(ECGChannelType.valueOf(deviceForm.getChannelType()));
                ecgDevice.setCpuId(deviceForm.getCpuId());

                ecgDeviceService.save(ecgDevice);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new MutilDeviceServiceException(ResponseEnum.ServerError);
            }
        }
    }

    @Override
    public void bindDevice(Integer patientId, String deviceId) {
        Device device = getOne(new QueryWrapper<Device>().eq("numeration", deviceId));
        if (device.getPatientId().intValue() == patientId.intValue()) {
            return;
        }

        Integer deviceTypeId = (Integer) device.getDeviceTypeId().getValue();

        Device preBound = getOne(new QueryWrapper<Device>().eq("patient_id", patientId).eq("device_type_id", deviceTypeId));

        if (preBound != null) {
            device = new Device();
            device.setPatientId(0);
            update(device, new QueryWrapper<Device>().eq("patient_id", patientId).eq("device_type_id", deviceTypeId));
            sessionManager.removeSession(preBound.getNumeration());
        }

        try {
            device.setPatientId(patientId);
            update(device, new QueryWrapper<Device>().eq("numeration", deviceId));
        } catch (Exception e) {
            e.printStackTrace();
            throw new MutilDeviceServiceException(ResponseEnum.ServerError);
        }

        if (DeviceType.XM_BP.getValue().equals(deviceTypeId + "")) {
            AutoDetectCmdDto autoDetectCmd = new AutoDetectCmdDto();
            autoDetectCmd.setDeviceId(deviceId);
            autoDetectCmd.setRectify(1);

            xmBpDeviceService.setRectify(autoDetectCmd);
        }

        //换绑重启设备
        if (DeviceType.XM_BP.getValue().equals(deviceTypeId) || DeviceType.ECG_DEVICE.getValue().equals(deviceTypeId)) {
            sessionManager.removeSession(deviceId);
        }

    }

    @Override
    public void deleteDevices(Integer[] ids) {
        baseMapper.batchUpdateStatus(ids);
    }

    @Override
    public List<DeviceVO> getBoundDevices(Integer patientId) {
        List<DeviceVO> devices = baseMapper.selectBoundDevicesByPatientId(patientId);

        List<String> deviceIds = devices.stream().map(DeviceVO::getNumeration).collect(Collectors.toList());

        Collection<String> onlineDeviceIds = sessionManager.getOnlineDeviceIds(deviceIds);

        if (devices != null && devices.size() > 0 && onlineDeviceIds != null && onlineDeviceIds.size() > 0) {
            for (DeviceVO deviceVO : devices) {
                for (String onlineDeviceId : onlineDeviceIds) {
                    if (deviceVO.getNumeration().equals(onlineDeviceId)) {
                        deviceVO.setState(1);
                        onlineDeviceIds.remove(onlineDeviceId);
                        break;
                    }
                }
            }
        }

        return devices;
    }

    @Override
    public List<DeviceCountVO> getDeviceCount() {
        List<DeviceCountVO> deviceCountVOList = new ArrayList<>();
        List<DeviceCountDTO> deviceCountDTOList = baseMapper.selectDeviceCount();

        for (DeviceCountDTO deviceCountDTO : deviceCountDTOList) {
            DeviceCountVO deviceCountVO = new DeviceCountVO();
            deviceCountVO.setDeviceType(deviceCountDTO.getDeviceType());
            deviceCountVO.setTotalCount(deviceCountDTO.getNumerations().size());
            switch (deviceCountDTO.getDeviceType()) {
                case BP_DEVICE:
                    deviceCountVO.setOnlineCount(lanyaDeviceService.getOnlineBp().size());
                    break;
                case SPO_DEVICE:
                    deviceCountVO.setOnlineCount(lanyaDeviceService.getOnlineSpo().size());
                    break;
                default:
                    deviceCountVO.setOnlineCount(sessionManager.getOnlineDeviceIds(deviceCountDTO.getNumerations()).size());
            }

            deviceCountVOList.add(deviceCountVO);
        }

        return deviceCountVOList;
    }

    @Override
    public List<Device> getTypeDevice(DeviceType deviceType, Integer pushId, Integer userId) {

        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("device_type_id", deviceType.getValue());
        if (userId != 1) {
            queryWrapper.eq("user_id", userId);
        }
        List<Device> list = baseMapper.selectList(appendState(queryWrapper));
        QueryWrapper queryWrapper1 = new QueryWrapper();
        queryWrapper1.eq("push_id", pushId);
        List<TPushDevice> tPushDeviceList = tPushDeviceService.list(appendState(queryWrapper1));
        for (int i = 0; i < list.size(); i++) {
            for (TPushDevice tPushDevice : tPushDeviceList
                    ) {
                if (list.get(i).getId().equals(tPushDevice.getDeviceId())) {
                    list.remove(i);
                }
            }
        }
        return list;
    }

    @Override
    public void configEcgDevice(ConfigEcgDeviceForm configEcgDeviceForm) {

        // 1、获取配置设的channel
        Channel channel = sessionManager.getChannel(configEcgDeviceForm.getDeviceId());
        if (channel == null) {
            throw new MutilDeviceServiceException(ResponseEnum.DeviceNotOnline);
        }

        // 2、发送配置数据包
        Body body = new Body();
        body.setCommand(Command.CONFIG);
        body.setDeviceId(configEcgDeviceForm.getDeviceId());
        ConfigBody configBody = new ConfigBody();
        configBody.setWifiSSid(configEcgDeviceForm.getSsid());
        configBody.setWifiPassword(configEcgDeviceForm.getPassword());
        configBody.setHeartChannel(configEcgDeviceForm.getHeartChannel());
        configBody.setServerIp(configEcgDeviceForm.getServerIp());
        configBody.setServerPort(configEcgDeviceForm.getServerPort());
        configBody.setWifiChannel(configEcgDeviceForm.getWifiChannel());
        body.setConfigBody(configBody);
        MpPacket packet = new MpPacket().push(com.mlnx.tp.base.model.DeviceType.SERVER, body);
        packet.getHeader().setQoS(QoS.LEAST_ONE);
        channel.writeAndFlush(packet);
    }

    @Override
    public List<Device> getUnbindGroupDevice() {

        List<Device> list = baseMapper.selectList(appendState(new QueryWrapper<Device>().eq("group_id", -1)));

        return list;
    }

    @Override
    public void bindDeviceByGroupId(Integer patientId, Integer groupId) {

        baseMapper.update(new Device().setPatientId(patientId), new QueryWrapper<Device>().eq("group_id", groupId));

    }

    @Override
    public void unbindDevice(String deviceId) {
        baseMapper.update(new Device().setGroupId(-1), new QueryWrapper<Device>().eq("numeration", deviceId));

    }

    @Override
    public List<DeviceGroupVO2> getAllGroupInfo() {
        return baseMapper.getDevicesByGroup();
    }

    @Override
    public DeviceGroupDto getOtherDevice(String deviceId) {
        Map<String, String> map = new HashMap<>();
        DeviceGroupDto deviceGrpupDto = new DeviceGroupDto();
        Device device = baseMapper.selectOne(new QueryWrapper<Device>().eq("numeration", deviceId));
        if (device != null) {
            if (device.getGroupId() == -1) {
                throw new MutilDeviceServiceException(ResponseEnum.UnBindDeviceGroup.getCode(),
                        ResponseEnum.UnBindDeviceGroup.getMsg());
            } else {
                deviceGrpupDto.setPatientId(device.getPatientId());
                List<Device> list = baseMapper.selectList(new QueryWrapper<Device>().eq("group_id", device.getGroupId()));
                if (list.size() > 0) {
                    for (Device device1 : list
                            ) {
                        if (device1.getDeviceTypeId() == DeviceType.ECG_DEVICE) {
                            map.put("ECG", device1.getNumeration());
                        } else if (device1.getDeviceTypeId() == DeviceType.YOUR_BP) {
                            map.put("BP", device1.getNumeration());
                        } else if (device1.getDeviceTypeId() == DeviceType.SPO_DEVICE) {
                            map.put("SPO", device1.getNumeration());
                        }
                    }
                    deviceGrpupDto.setDeviceId(map);


                }
                return deviceGrpupDto;
            }
        } else {
            throw new MutilDeviceServiceException(ResponseEnum.DeviceUnExisted.getCode(),
                    ResponseEnum.DeviceUnExisted.getMsg());
        }

    }


}
